package com.googlecode.continuity.core.server.mvc;

import java.util.*;

import org.acegisecurity.context.SecurityContextHolder;
import com.googlecode.continuity.core.server.security.SecurityUserToken;

/**
 * ContinuityModel serves as a model that is returned by a page controller to construct the view.  This class provides
 * methods to simplify common tasks that occur during the construction of a model in the Continuity system, such as
 * template related tasks and communicating with GWT modules on the constructed page.  In addition, a few properties are
 * provided for every use of the model such as information on the user currently logged in.
 *
 * @author Peter Schmitt <aragos@aragos.de>
 */
public class ContinuityModel extends HashMap<String, Object> {
  /**
   * Constructs a new prepopulated model.
   */
  public ContinuityModel() {
    populateModel(this);
  }

  /**
   * Adds a template to be loaded in the right bar of the page.
   *
   * @param template template path
   */
  public void addRightBarTemplate(String template) {
    if (!containsKey("rightBar")) {
      put("rightBar", new LinkedList());
    }
    ((List<String>) get("rightBar")).add(template);
  }

  /**
   * Adds a template to be loaded in the left bar of the page.
   *
   * @param template template path
   */
  public void addLeftBarTemplate(String template) {
    if (!containsKey("leftBar")) {
      put("leftBar", new LinkedList());
    }
    ((List<String>) get("leftBar")).add(template);
  }

  /**
   * Adds a property that can be accessed by GWT modules.
   *
   * @param property property identifier
   * @param value property value
   */
  public void setGWTProperty(String property, String value) {
    if (!containsKey("gwtProperties")) {
      put("gwtProperties", new HashMap<String, String>());
    }
    ((Map<String, String>) get("gwtProperties")).put(property, value);
  }

  /**
   * Adds a GWT entry point to be called on page load.
   *
   * @param moduleName fully qualified type name of the entry point to be loaded
   * @see com.googlecode.continuity.core.client.UIEntryPoint
   */
  public void addGWTEntryPoint(String moduleName) {
    if (!containsKey("gwtEntryPoints")) {
      put("gwtEntryPoints", new HashSet<String>());
    }
    ((Set<String>) get("gwtEntryPoints")).add(moduleName);
  }

  /**
   * Populates the given model with a few common values:
   * <ul>
   *   <li><b>anonymous</b>: true if no user is logged in, false otherwise</li>
   *   <li><b>currentUser</b>: current user object, only available if <i>anonymous</i> is false</li>
   *   <li><b>root</b>: root path for this application</li>
   * </ul>
   *
   * @param model
   */
  public static void populateModel(Map<String, Object> model) {
    Object user = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    model.put("anonymous", !(user instanceof SecurityUserToken));
    if (user instanceof SecurityUserToken) {
      model.put("currentUser", ((SecurityUserToken) user).getUser());
    }
    // todo: make configurable!
    model.put("root", "/continuity/");
  }
}
